/**
 * \file Message.h
 * \brief Message pipe IPC mechanism
 * \author Corey Tabaka
 */

/*
   Copyright 2005 Corey Tabaka

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#ifndef __KERNEL_MESSAGE_H__
#define __KERNEL_MESSAGE_H__

#include <ktypes.h>
#include <Sync.h>
#include <Reference.h>

#define MESSAGE_BUFFER_INITIAL_SIZE 8

class MessagePipe;
DEF_REF_TYPE(MessagePipe);

class MessageBuffer {
	private:
	
	uint32 length;
	uint32 capacity;
	uint8 *data;
	
	//Mutex mutex;
	InterruptLock mutex;
	Semaphore full;
	Semaphore empty;
	
	void checkBuffer(uint32 len);
	
	public:
	
	MessageBuffer(uint32 cap);
	~MessageBuffer(void);
	
	void read(uint8 *p, uint32 len);
	void write(const uint8 *p, uint32 len);
	
	void read(uint8 *h, uint32 hlen, uint8 *p, uint32 len);
	void write(const uint8 *h, uint32 hlen, const uint8 *p, uint32 len);
};

class MessagePipe {
	private:
	
	Mutex senders;
	Mutex receivers;
	
	MessageBuffer sendBuffer;
	MessageBuffer replyBuffer;
	
	volatile int valid;
	
	public:
	
	MessagePipe(void);
	virtual ~MessagePipe(void);
	
	/*
	 * Reference Validation
	 * Allows a message queue to be forced invalid, even though there are
	 * still references to it.
	 */
	bool isValid(void);
	void invalidate(void);
	
	/*
	 * Raw data methods
	 */
	
	int receive(void *data, uint32 len);
	int reply(const void *data, uint32 len);
	
	int send(const void *sdata, uint32 slen, void *rdata, uint32 rlen);
	
	/*
	 * Typed data methods
	 */
	int receive(void *header, uint32 hlen, void *data, uint32 dlen);
	int reply(const void *header, uint32 hlen, const void *data,
		uint32 dlen);
	
	int send(const void *sheader, uint32 shlen, const void *sdata,
		uint32 slen, void *rheader, uint32 rhlen, void *rdata, uint32 rlen);
};

#endif
